package com.shouer.doc.request;

import android.content.Context;
import android.content.res.Resources;
import android.util.Base64;
import android.util.Log;

import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.shouer.doc.common.ShouerConst;
import com.shouer.doc.common.util.Tools;

import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.security.cert.CertificateFactory;
import java.util.Map;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;

import okhttp3.OkHttpClient;
import com.shouer.doc.R;

/**
 * Created by ZXL on 2016/11/12.
 */

public class RequestUtil {

    public static final boolean NEED_ENCRYP_HEAD = false;

    public static final boolean NEED_DECRYPT_RESPONSE = false;

    public static volatile RequestQueue requestQueue;

    private static volatile OkHttpClient okHttpClient;


    public static RequestQueue getRequestQueue(Context context) {
        if (null == requestQueue) {
            synchronized (RequestUtil.class) {
                if (requestQueue == null) {
                    ShouerConst.DEFAULT_UUID = Tools.getUUID(context);
                    requestQueue = Volley.newRequestQueue(context,null,true,R.raw.srca);
                }
            }
        }

        return requestQueue;
    }

    public static OkHttpClient getOkHttpClient(Context context) {

        if (null == okHttpClient) {
            synchronized (RequestUtil.class) {
                if (okHttpClient == null) {

                    InputStream inputStream = null;
                    SSLSocketFactory sslSocketFactory = null;
                    try {
                        inputStream = context.getResources().openRawResource(R.raw.srca);
                        sslSocketFactory = getCertificates(inputStream);
                    } catch (Resources.NotFoundException e) {
                        Log.e(RequestUtil.class.getSimpleName(), "IOException:" + e.toString());
                    } finally {
                        if (null != inputStream) {
                            try {
                                inputStream.close();
                            } catch (IOException e) {
                                Log.e(RequestUtil.class.getSimpleName(), "inputStream close():" + e.toString());
                            }
                        }
                    }
                    if (null != sslSocketFactory) {

                        okHttpClient = new OkHttpClient.Builder()
                                .sslSocketFactory(sslSocketFactory)
                                .build();
                    } else {
                        okHttpClient = new OkHttpClient();
                    }

                }
            }
        }

        return okHttpClient;
    }
    public static Request sendRequest(Context context, Map<String, String> requestParam, BaseRequest request) {
        request.setPostParam(requestParam);
        return getRequestQueue(context).add(request);
    }

    public static Request sendRequest(Context context, Request request) {
        return getRequestQueue(context).add(request);
    }


    public static String signMsg(String msg) {
        String sign = "";

        try {
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            md5.update(msg.getBytes());
            byte[] buffer = md5.digest();
            sign = bcd2Str(buffer);
        } catch (Exception e) {
            Log.e(RequestUtil.class.getSimpleName(), "signMsg():" + e.toString());
        }

        return sign;
    }

    private static String bcd2Str(byte[] bytes) {
        char temp[] = new char[bytes.length * 2], val;

        for (int i = 0; i < bytes.length; i++) {
            val = (char) (((bytes[i] & 0xf0) >> 4) & 0x0f);
            temp[i * 2] = (char) (val > 9 ? val + 'A' - 10 : val + '0');

            val = (char) (bytes[i] & 0x0f);
            temp[i * 2 + 1] = (char) (val > 9 ? val + 'A' - 10 : val + '0');
        }

        return new String(temp);
    }

    public static String getChallenge(int index) {
        return WORD_TABLE[index];
    }

    private static final String[] WORD_TABLE = {
            "de facto",
            "pectic",
            "decade",
            "brokerage",
            "panic",
            "dichloroethylene",
            "periodic",
            "frequency",
            "Fourier",
            "mixture"};

    public static String genHeader(String timeStamp, String method) {
        String header = null;

        try {
            // long number1 = Math.abs(UUID.fromString(uuid).getLeastSignificantBits());
            long number1 = Long.valueOf(timeStamp);
            int index1 = (int) (number1 % 10);
            String msg = ShouerConst.APP_ID + ShouerConst.APP_VERSION + method + timeStamp + ShouerConst.DEFAULT_UUID + getChallenge(index1);
            String sign = signMsg(msg);
            header = String.format(ShouerConst.jsonHeaderParam, ShouerConst.APP_ID, ShouerConst.APP_VERSION, method, timeStamp, ShouerConst.DEFAULT_UUID, sign, "zh-hans");
        } catch (Exception e) {
            Log.e("getheader", "genHeader():" + e.toString());
        }

        return header;
    }

    public static String encryptMessage(String timeStamp, String header, String body) {
        String cryptedMessage = null;

        StringBuffer pading192String = new StringBuffer(header);
        for (int i = 0; i < 192 - header.length(); i++) {
            pading192String.append("0");
        }

        if (NEED_ENCRYP_HEAD) {
            try {
                long number2 = Long.valueOf(timeStamp);
                int index2 = (int) (number2 % 10);
                String key = getCryptKey(getChallenge(index2));
                byte[] cryptedBuffer = AESEncrypt(body.getBytes("UTF-8"), key.getBytes());
                String bodyString = new String(Base64.encode(cryptedBuffer, Base64.DEFAULT));
                cryptedMessage = pading192String + bodyString;
            } catch (Exception e) {
                Log.e("encryptMessage", "encryptMessage()" + e.toString());
            }

        } else {
            cryptedMessage = pading192String + body;
        }

        return cryptedMessage;
    }

    public static String getCryptKey(String word) {
        String key = "";

        try {
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            md5.update(word.getBytes());
            byte[] buffer = md5.digest();
            key = bcd2Str(buffer).substring(16);
        } catch (Exception e) {
            Log.e("getCryptKey", "getCryptKey " + e);
        }

        return key;
    }

    public static byte[] AESEncrypt(byte[] src, byte[] key) {
        byte[] crypted = null;

        try {

            SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            IvParameterSpec ips = new IvParameterSpec(ShouerConst.iv.getBytes());
            cipher.init(Cipher.ENCRYPT_MODE, keySpec, ips);

            crypted = cipher.doFinal(src);

        } catch (Exception e) {
            Log.e("AESEncrypt", "AESEncrypt " + e);
        }

        return crypted;
    }

    public static byte[] AESDecrypt(byte[] src, byte[] key) {
        byte[] data = null;

        try {

            SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            IvParameterSpec ips = new IvParameterSpec(ShouerConst.iv.getBytes());
            cipher.init(Cipher.DECRYPT_MODE, keySpec, ips);

            data = cipher.doFinal(src);

        } catch (Exception e) {
            Log.e("AESDecrypt", "AESDecrypt " + e);
        }

        return data;
    }

    public static SSLSocketFactory getCertificates(InputStream... certificates) {

        Log.i(RequestUtil.class.getSimpleName(),"------getCertificates------");
        try {
            CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            keyStore.load(null);
            int index = 0;
            for (InputStream certificate : certificates) {
                String certificateAlias = Integer.toString(index++);
                keyStore.setCertificateEntry(certificateAlias, certificateFactory.generateCertificate(certificate));

                try {
                    if (certificate != null)
                        certificate.close();
                } catch (IOException e) {
                }
            }

            SSLContext sslContext = SSLContext.getInstance("TLS");

            TrustManagerFactory trustManagerFactory =
                    TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());

            trustManagerFactory.init(keyStore);
            sslContext.init
                    (
                            null,
                            trustManagerFactory.getTrustManagers(),
                            new SecureRandom()
                    );

            return sslContext.getSocketFactory();

        } catch (Exception e) {
            e.printStackTrace();
        }


        return null;

    }
}
